// Copyright (c) Appeon. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Threading;
using System.Threading.Tasks;

namespace SnapObjects.Data
{
    /// <summary>
    ///     SqlModelMapper is a transaction-oriented data manipulation component compliant with .NET Standard. 
    ///     It can build models with data from multiple tables, support nested levels of relationships, and 
    ///     provide explicit and implicit transaction management for business entities (i.e. a top-level object 
    ///     and all of its children).When SqlModelMapper is used to save data, it can automatically commit all 
    ///     tracked data operations in one transaction to achieve data integrity.
    /// </summary>
    public interface ISqlModelMapper
    {
        /// <summary>
        ///     Retrieves data according to the SQL query defined in a TModel class.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <param name="parameters">
        ///     (Optional) One or more values that you want to use as retrieval arguments in the SQL SELECT 
        ///     statement defined in TModel.
        /// </param>
        /// <returns>Returns a <see cref="ILoadable{TModel}"/> 
        ///     object whose methods can be used to further obtain the result set, or perform data operations 
        ///     such as embedded queries.
        /// </returns>
        ILoadable<TModel> Load<TModel>(params object[] parameters);

        /// <summary>
        ///     Asynchronously retrieves data according to the SQL query defined in a TModel class.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <param name="parameters">
        ///     (Optional) One or more values that you want to use as retrieval arguments in the SQL SELECT 
        ///     statement defined in TModel.
        /// </param>
        /// <returns>
        ///     Returns a task that represents the asynchronous operation. 
        /// </returns>
        Task<ILoadable<TModel>> LoadAsync<TModel>(params object[] parameters);


        /// <summary>
        ///     Asynchronously retrieves data according to the SQL query defined in a TModel class.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <param name="parameters">
        ///     One or more values that you want to use as retrieval arguments in the SQL SELECT 
        ///     statement defined in TModel.
        /// </param>
        /// <param name="cancellationToken">
        ///      A cancellation token that can be used by other objects or threads to receive notice of cancellation.
        /// </param>
        /// <returns>
        ///     Returns a task that represents the asynchronous operation. 
        /// </returns>
        Task<ILoadable<TModel>> LoadAsync<TModel>(object[] parameters, CancellationToken cancellationToken);

        /// <summary>
        ///     Retrieves data for the specified page according to the SQL query defined in a TModel class.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <param name="currentIndex">The zero-based index of the first record in the page.</param>
        /// <param name="pageSize">The count of rows in each page.</param>
        /// <param name="parameters">
        ///     (Optional) One or more values that you want to use as retrieval arguments in the SQL SELECT 
        ///     statement defined in TModel.
        /// </param>
        /// <returns>
        ///     Returns the <see cref="ILoadable{TModel}"/> interface whose methods can be used to further obtain the 
        ///     result set, or perform data operations such as embedded queries.
        /// </returns>
        ILoadable<TModel> LoadByPage<TModel>(int currentIndex, int pageSize, params object[] parameters);

        /// <summary>
        ///     Asynchronously retrieves data for the specified page according to the SQL query defined in a TModel class.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <param name="currentIndex">The zero-based index of the first record in the page.</param>
        /// <param name="pageSize">The count of rows in each page.</param>
        /// <param name="parameters">
        ///     (Optional) One or more values that you want to use as retrieval arguments in the SQL SELECT 
        ///     statement defined in TModel.
        /// </param>
        /// <returns>
        ///     Returns a task that represents the asynchronous operation.
        /// </returns>
        Task<ILoadable<TModel>> LoadByPageAsync<TModel>(
            int currentIndex, int pageSize, params object[] parameters);

        /// <summary>
        ///     Asynchronously retrieves data for the specified page according to the SQL query defined in a TModel class.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <param name="currentIndex">The zero-based index of the first record in the page.</param>
        /// <param name="pageSize">The count of rows in each page.</param>
        /// <param name="parameters">
        ///     One or more values that you want to use as retrieval arguments in the SQL SELECT 
        ///     statement defined in TModel.
        /// </param>
        /// <param name="cancellationToken">
        ///      A cancellation token that can be used by other objects or threads to receive notice of cancellation.
        /// </param>
        /// <returns>
        ///     Returns a task that represents the asynchronous operation.
        /// </returns>
        Task<ILoadable<TModel>> LoadByPageAsync<TModel>(
            int currentIndex, int pageSize, object[] parameters, CancellationToken cancellationToken);

        /// <summary>
        ///     Retrieves data from the database according to the SQL query (without the Where clause) defined by 
        ///     the primary table in a TModel class.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <returns>
        ///     Returns the <see cref="ILoadable{TModel}"/> interface whose methods can be used to further obtain the 
        ///     result set, or perform data operations such as embedded queries.
        /// </returns>
        ILoadable<TModel> LoadAll<TModel>();

        /// <summary>
        ///     Asynchronously retrieves data from the database according to the SQL query (without the Where clause) defined by 
        ///     the primary table in a TModel class.   
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <returns>Returns a task that represents the asynchronous operation.</returns>
        Task<ILoadable<TModel>> LoadAllAsync<TModel>();

        /// <summary>
        ///     Asynchronously retrieves data from the database according to the SQL query (without the Where clause) defined by 
        ///     the primary table in a TModel class.   
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <param name="cancellationToken">
        ///     A cancellation token that can be used by other objects or threads to receive notice of cancellation.
        /// </param>
        /// <returns>Returns a task that represents the asynchronous operation.</returns>
        Task<ILoadable<TModel>> LoadAllAsync<TModel>(CancellationToken cancellationToken);

        /// <summary>
        ///     Retrieves data for the specified page according to the SQL query (without the Where clause) 
        ///     defined by the primary table in a TModel class.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <param name="currentIndex">The zero-based index of the first record in the page.</param>
        /// <param name="pageSize">The count of rows in each page.</param>
        /// <returns>
        ///     Returns the <see cref="ILoadable{TModel}"/> interface whose methods can be used to further obtain the 
        ///     result set, or perform data operations such as embedded queries.
        /// </returns>
        ILoadable<TModel> LoadAllByPage<TModel>(int currentIndex, int pageSize);

        /// <summary>
        ///     Asynchronously retrieves data for the specified page according to the SQL query (without the Where clause) 
        ///     defined by the primary table in a TModel class.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <param name="currentIndex">The zero-based index of the first record in the page.</param>
        /// <param name="pageSize">The count of rows in each page.</param>
        /// <returns>
        ///     Returns a task that represents the asynchronous operation.
        /// </returns>
        Task<ILoadable<TModel>> LoadAllByPageAsync<TModel>(int currentIndex, int pageSize);

        /// <summary>
        ///     Asynchronously retrieves data for the specified page according to the SQL query (without the Where clause) 
        ///     defined by the primary table in a TModel class.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <param name="currentIndex">The zero-based index of the first record in the page.</param>
        /// <param name="pageSize">The count of rows in each page.</param>
        /// <param name="cancellationToken">
        ///     A cancellation token that can be used by other objects or threads to receive notice of cancellation.
        /// </param>
        /// <returns>
        ///     Returns a task that represents the asynchronous operation.
        /// </returns>
        Task<ILoadable<TModel>> LoadAllByPageAsync<TModel>(
            int currentIndex, int pageSize, CancellationToken cancellationToken);

        /// <summary>
        ///     Retrieves data according to the primary key defined in a TModel class.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <param name="parameters">
        ///     One or more values that you want to use as retrieval arguments in the SQL SELECT statement defined by 
        ///     the primary table and its primary key(s) in TModel.
        /// </param>
        /// <returns>
        ///     Returns the <see cref="ILoadable{TModel}"/> interface whose methods can be used to further obtain the result set, or perform 
        ///     data operations such as embedded queries.
        /// </returns>
        ILoadable<TModel> LoadByKey<TModel>(params object[] parameters);

        /// <summary>
        ///     Asynchronously retrieves data according to the primary key defined in a TModel class.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <param name="parameters">
        ///     One or more values that you want to use as retrieval arguments in the SQL SELECT statement defined by 
        ///     the primary table and its primary key(s) in TModel.
        /// </param>
        /// <returns>
        ///     Returns a task that represents the asynchronous operation.
        /// </returns>
        Task<ILoadable<TModel>> LoadByKeyAsync<TModel>(params object[] parameters);

        /// <summary>
        ///     Asynchronously retrieves data according to the primary key defined in a TModel class.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <param name="parameters">
        ///     One or more values that you want to use as retrieval arguments in the SQL SELECT statement defined by 
        ///     the primary table and its primary key(s) in TModel.
        /// </param>
        /// <param name="cancellationToken">
        ///     A cancellation token that can be used by other objects or threads to receive notice of cancellation.
        /// </param>
        /// <returns>
        ///     Returns a task that represents the asynchronous operation.
        /// </returns>
        Task<ILoadable<TModel>> LoadByKeyAsync<TModel>(object[] parameters, CancellationToken cancellationToken);

        /// <summary>
        ///     Obtains an <see cref="IEmbeddedLoadable{TModel}"/> object, which can be used to load the embedded property 
        ///     of a TModel instance.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <param name="model">
        ///     A TModel instance which has defined one or more embedded properties (by applying the ModelEmbedded 
        ///     attribute or the SqlEmbedded attribute).
        /// </param>
        /// <param name="parameters">
        ///     (Optional) One or more values that you want to use as retrieval arguments in the SQL SELECT 
        ///     statement defined in TModel.These parameters will not be used to retrieve data for all properties 
        ///     in TModel object, but used to process the embedded property), because the embedded property) 
        ///     may have reference to these TModel parameters.
        /// </param>
        /// <returns>Returns an interface that can load one or more embedded properties) of a TModel object.</returns>
        IEmbeddedLoadable<TModel> LoadEmbedded<TModel>(TModel model, params object[] parameters);

        /// <summary>
        ///     Tracks an <see cref="Action{ISaveContext}"/> object. The Action will be called when 
        ///     ISqlModelMapper.SaveChanges method is called.
        /// </summary>
        /// <param name="saveAction">
        ///     An <see cref="Action{ISaveContext}"/> object that needs to be tracked. Please avoid calling any 
        ///     tracking method of the current ISqlModelMapper object in the script of the Action.
        /// </param>
        /// <returns>Returns the current <see cref="ISqlModelMapper"/> object, which can be used for executing other methods.</returns>
        ISqlModelMapper Track(Action<ISaveContext> saveAction);

        /// <summary>
        ///     Tracks an IMapperTrackable object. When ISqlModelMapper.SaveChanges method is called, 
        ///     the SaveChanges method of this object will be called.
        /// </summary>
        /// <param name="mapperTrackable">The IMapperTrackable object to be tracked.</param>
        /// <param name="saveParms">The parameters used by the SaveChanges method of IMapperTrackable.</param>
        /// <returns>Returns the current <see cref="ISqlModelMapper"/> object, which can be used to execute other methods.</returns>
        ISqlModelMapper Track(IMapperTrackable mapperTrackable, params object[] saveParms);

        /// <summary>
        ///     Tracks a database table operation (insert, update, or delete). The data state determines which type of 
        ///     operation (insert, update, or delete) to be performed. The data to be manipulated is cached in the 
        ///     TModel object. When ISqlModelMapper.SaveChanges method is called, a SQL statement (INSERT, UPDATE or DELETE) 
        ///     will be first generated using the data cached in the TModel object and the mapping information defined 
        ///     in TModel class, and then executed.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <param name="modelEntry">
        ///     An <see cref="IModelEntry{TModel}"/> object including data and state.
        /// </param>
        /// <returns>Returns a tracked model object which includes the data from the <see cref="IModelEntry{TModel}"/> object.</returns>
        TModel Track<TModel>(IModelEntry<TModel> modelEntry);

        /// <summary>
        ///     Tracks a database table operation (insert, update, or delete) and an <see cref="Action{ISaveContext}"/> object. 
        ///     The data state determines which type of operation (insert, update, or delete) to be performed. 
        ///     The data to be manipulated is cached in the TModel object. When ISqlModelMapper.SaveChanges method 
        ///     is called, a SQL statement (INSERT, UPDATE or DELETE) will be first generated using the data cached 
        ///     in the TModel object and the mapping information defined in TModel class, and then executed; 
        ///     and after that, the <see cref="Action{ISaveContext}"/> object will be called.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <param name="modelEntry">An <see cref="IModelEntry{TModel}"/> object including data and state.</param>
        /// <param name="afterSaveAction">An <see cref="Action{ISaveContext}"/> object that needs to be tracked.</param>
        /// <returns>
        ///     Returns a tracked TModel instance which includes the data from the <see cref="IModelEntry{TModel}"/> object.
        /// </returns>
        TModel Track<TModel>(IModelEntry<TModel> modelEntry, Action<ISaveContext> afterSaveAction);

        /// <summary>
        ///     Tracks one or more database table operations (insert, update or delete). The data state 
        ///     determines which type of operation will be performed. The data to be manipulated is cached 
        ///     in the TModel objects. When ISqlModelMapper.SaveChanges method is called, one or more SQL
        ///     statements (INSERT, UPDATE or DELETE) will be generated using the data cached in the TModel 
        ///     objects and the mapping information defined in TModel class, and then executed.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <param name="modelEntries">A sequence of <see cref="IModelEntry{TModel}"/> objects containing data and state.</param>
        /// <returns>A list of TModel objects which have been tracked by this method.</returns>
        IList<TModel> TrackRange<TModel>(IEnumerable<IModelEntry<TModel>> modelEntries);

        /// <summary>
        ///     Tracks an insert, update or delete operation to the master table, when working with 
        ///     multiple models which are in the master-detail relationship. The data state determines 
        ///     which type of operation (insert, update or delete) will be performed. The data to be 
        ///     manipulated is cached in the TModel object. When ISqlModelMapper.SaveChanges method is 
        ///     called, a SQL statement (INSERT, UPDATE or DELETE) will be first generated using the 
        ///     data cached in the TModel object and the mapping information defined in TModel class, and then executed.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <param name="modelEntry">A <see cref="IModelEntry{TModel}"/> object which includes the data and state of the master model.</param>
        /// <returns>An <see cref="IDetailTracker{TModel}"/> object that can be used to track the detail model.</returns>
        IDetailTracker<TModel> TrackMaster<TModel>(IModelEntry<TModel> modelEntry);

        /// <summary>
        ///     Tracks an insert, update or delete operation to the master table and an <see cref="Action{ISaveContext}"/> object, 
        ///     when working with multiple models which are in the master-detail relationship. The data state 
        ///     determines which type of operation (insert, update or delete) will be performed. The data to be 
        ///     manipulated is cached in the TModel object. When ISqlModelMapper.SaveChanges method is called, 
        ///     a SQL statement (INSERT, UPDATE or DELETE) will be first generated using the data cached in the 
        ///     TModel object and the mapping information defined in TModel class, and then executed; and after that,
        ///     the <see cref="Action{ISaveContext}"/> object will be called.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <param name="modelEntry">An <see cref="IModelEntry{TModel}"/> object which includes the data and state of the master model.</param>
        /// <param name="afterSaveAction">An c object that needs to be tracked.</param>
        /// <returns>An interface that can be used to track the detail model.</returns>
        IDetailTracker<TModel> TrackMaster<TModel>(IModelEntry<TModel> modelEntry, Action<ISaveContext> afterSaveAction);

        /// <summary>
        ///     Tracks a database table insert operation. The data that will be inserted into the 
        ///     database table is cached in the TModel object. When ISqlModelMapper.SaveChanges 
        ///     method is called, a SQL INSERT statement will be first generated using the data 
        ///     cached in the TModel object and the mapping information defined in TModel class, and then executed.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <param name="model">A TModel instance used for adding a record.</param>
        /// <returns>Returns the current <see cref="ISqlModelMapper"/> object, which can be used for executing other methods.</returns>
        ISqlModelMapper TrackCreate<TModel>(TModel model);

        /// <summary>
        ///     Tracks a database table insert operation and an <see cref="Action{ISaveContext}"/> object. 
        ///     The data that will be inserted into the database table is cached in the TModel 
        ///     object. When ISqlModelMapper.SaveChanges method is called, a SQL INSERT statement 
        ///     will be first generated using the data cached in the TModel object and the 
        ///     mapping information defined in TModel class, and then executed. After that, 
        ///     the <see cref="Action{ISaveContext}"/> object will be called.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <param name="model">A model instance used for adding a record.</param>
        /// <param name="afterSaveAction">An <see cref="Action{ISaveContext}"/> object that needs to be tracked.</param>
        /// <returns>Returns the current <see cref="ISqlModelMapper"/> object, which can be used for executing other methods.</returns>
        ISqlModelMapper TrackCreate<TModel>(TModel model, Action<ISaveContext> afterSaveAction);

        /// <summary>
        ///     Tracks a database table update operation. The data that will be updated to the database 
        ///     table is cached in the TModel object. When ISqlModelMapper.SaveChanges method is called, 
        ///     a SQL UPDATE statement will be first generated using the data cached in the TModel object 
        ///     and the mapping information defined in TModel class, and then executed.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <param name="model">The TModel object that contains the data you want to update to database.</param>
        /// <returns>Returns the current <see cref="ISqlModelMapper"/> object, which can be used for executing other methods.</returns>
        ISqlModelMapper TrackUpdate<TModel>(TModel model);

        /// <summary>
        ///     Tracks a database table update operation and an <see cref="Action{ISaveContext}"/> object. The data that 
        ///     will be updated to the database table is cached in the TModel object. When ISqlModelMapper.SaveChanges 
        ///     method is called, a SQL UPDATE statement will be first generated using the data cached in the 
        ///     TModel object and the mapping information defined in TModel class, and then executed. After that, 
        ///     the <see cref="Action{ISaveContext}"/> object will be called.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <param name="model">The TModel object that contains the data you want to update to database.</param>
        /// <param name="afterSaveAction">An <see cref="Action{ISaveContext}"/> object that needs to be tracked.</param>
        /// <returns>Returns the current <see cref="ISqlModelMapper"/> object, which can be used for executing other methods.</returns>
        ISqlModelMapper TrackUpdate<TModel>(TModel model, Action<ISaveContext> afterSaveAction);

        /// <summary>
        ///     Tracks a database table update operation. The data that will be updated to the database table 
        ///     is cached in the modifiedModel and the original data is cached in the originalModel. 
        ///     When ISqlModelMapper.SaveChanges method is called, a SQL UPDATE statement will be first generated 
        ///     using the data cached in the modifiedModel , the data cached in the originalModel, and the mapping 
        ///     information defined in TModel class, and then executed.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <param name="originalModel">The TModel object that contains the original data you want to update.</param>
        /// <param name="modifiedModel">The TModel object that contains the modified data you want to update to database.</param>
        /// <returns>Returns the current <see cref="ISqlModelMapper"/> object, which can be used for executing other methods.</returns>
        ISqlModelMapper TrackUpdate<TModel>(TModel originalModel, TModel modifiedModel);

        /// <summary>
        ///     Tracks a database table update operation and an <see cref="Action{ISaveContext}"/> object. The data that will be 
        ///     updated to the database table is cached in the modifiedModel and the original data is cached in 
        ///     the originalModel. When ISqlModelMapper.SaveChanges method is called, a SQL UPDATE statement will 
        ///     be first generated using the data cached in the modifiedModel , the data cached in the originalModel, 
        ///     and the mapping information defined in TModel class, and then executed. After that, 
        ///     the <see cref="Action{ISaveContext}"/> object will be called.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <param name="originalModel">The TModel object that contains the original data you want to update.</param>
        /// <param name="modifiedModel">The TModel object that contains the modified data you want to update to database.</param>
        /// <param name="afterSaveAction">An <see cref="Action{ISaveContext}"/> object that needs to be tracked.</param>
        /// <returns>Returns the current <see cref="ISqlModelMapper"/> object, which can be used for executing other methods.</returns>
        ISqlModelMapper TrackUpdate<TModel>(TModel originalModel, TModel modifiedModel, Action<ISaveContext> afterSaveAction);

        /// <summary>
        ///     Tracks a database table delete operation. The data that will be deleted from the database 
        ///     table is cached in the TModel object. When ISqlModelMapper.SaveChanges method is called, 
        ///     a SQL DELETE statement will be first generated using the data cached in the TModel object 
        ///     and the mapping information defined in TModel class, and then executed.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <param name="model">The TModel instance that corresponds to the database record.</param>
        /// <returns>Returns an <see cref="ISqlModelMapper"/> object, which can be used for executing other methods.</returns>
        ISqlModelMapper TrackDelete<TModel>(TModel model);

        /// <summary>
        ///     Tracks a database table delete operation and an <see cref="Action{ISaveContext}"/> object. The data that will 
        ///     be deleted from the database table is cached in the TModel object. When ISqlModelMapper.SaveChanges 
        ///     method is called, a SQL DELETE statement will be first generated using the data cached in the 
        ///     TModel object and the mapping information defined in TModel class, and then executed; and after that, 
        ///     the <see cref="Action{ISaveContext}"/> object will be called.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <param name="model">The TModel instance that corresponds to the database record.</param>
        /// <param name="afterSaveAction">An <see cref="Action{ISaveContext}"/> object that needs to be tracked.</param>
        /// <returns>Returns an <see cref="ISqlModelMapper"/> object, which can be used for executing other methods.</returns>
        ISqlModelMapper TrackDelete<TModel>(TModel model, Action<ISaveContext> afterSaveAction);

        /// <summary>
        ///     Tracks one or more database table insert operations. The data that will be inserted into 
        ///     the database table is cached in the TModel object. When ISqlModelMapper.SaveChanges method 
        ///     is called, one or more SQL INSERT statements will be first generated using the data cached 
        ///     in the TModel object and the mapping information defined in TModel class, and then executed.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <param name="models">A collection of TModel type used for adding one or multiple records.</param>
        /// <returns>Returns an <see cref="ISqlModelMapper"/> object, which can be used for executing other methods.</returns>
        ISqlModelMapper TrackCreateRange<TModel>(IEnumerable<TModel> models);

        /// <summary>
        ///     Tracks one or more database table delete operations. The data that will be deleted from 
        ///     the database table is cached in the TModel object. When ISqlModelMapper.SaveChanges method 
        ///     is called, one or more SQL DELETE statements will be first generated using the data cached 
        ///     in the TModel object and the mapping information defined in TModel class, and then executed.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <param name="models">A collection of TModel type used for deleting one or multiple records.</param>
        /// <returns>Returns an <see cref="ISqlModelMapper"/> object, which can be used for executing other methods.</returns>
        ISqlModelMapper TrackDeleteRange<TModel>(IEnumerable<TModel> models);

        /// <summary>
        ///     Tracks one or more database table update operations. The data that will be updated to the
        ///     database table is cached in the TModel objects. When ISqlModelMapper.SaveChanges method is 
        ///     called, one or more SQL UPDATE statements will be first generated using the data cached in 
        ///     the TModel objects and the mapping information defined in TModel class, and then executed.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <param name="models">A sequence of TModel objects used for updating one or multiple records in database.</param>
        /// <returns>Returns the current <see cref="ISqlModelMapper"/> object, which can be used for executing other methods.</returns>
        ISqlModelMapper TrackUpdateRange<TModel>(IEnumerable<TModel> models);

        /// <summary>
        ///     Tracks a database table delete operation by the primary key. A SQL DELETE statement will
        ///     be generated using the primary key value(s) and the mapping information defined in TModel. 
        ///     When ISqlModelMapper.SaveChanges method is called, the SQL DELETE statement will be executed.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <param name="parameters">
        ///     (Optional) One or more primary key values that you want to use as arguments in the SQL DELETE statement.
        /// </param>
        /// <returns>Returns an <see cref="ISqlModelMapper"/> object, which can be used for executing other methods.</returns>
        ISqlModelMapper TrackDeleteByKey<TModel>(params object[] parameters);

        /// <summary>
        ///     Tracks a database table operation (insert, update or delete) using a raw SQL statement (INSERT, UPDATE, or DELETE). 
        ///     When ISqlModelMapper.SaveChanges method is called, the SQL statement will be executed.
        /// </summary>
        /// <param name="sqlText">
        ///     An SQL INSERT, UPDATE, or DELETE statement.
        ///     Use : or @ symbol at the beginning to represent the parameter required by the SQL statement.
        /// </param>
        /// <param name="parameters">
        ///     The arguments required by the SQL statement. The order of arguments here must be the same as the order of arguments in sqlText.
        /// </param>
        /// <returns>Returns an ISqlModelMapper object, which can be used for executing other methods.</returns>
        ISqlModelMapper TrackSqlCUD(string sqlText, params object[] parameters);

        /// <summary>
        ///     Tracks a database table insert operation. A SQL INSERT statement will be generated using the 
        ///     specified ISqlInsertBuilder object. When ISqlModelMapper.SaveChanges method is called, 
        ///     the SQL INSERT statement will be executed.
        /// </summary>
        /// <param name="insertBuilder">An ISqlInsertBuilder object used to build the SQL INSERT statement.</param>
        /// <param name="parameters">
        ///     (Optional) One or more values that you want to use as arguments in the SQL INSERT statement defined in insertBuilder.
        /// </param>
        /// <returns>Returns the current <see cref="ISqlModelMapper"/> object, which can be used for executing other methods.</returns>
        ISqlModelMapper TrackSqlBuilder(ISqlInsertBuilder insertBuilder, params object[] parameters);

        /// <summary>
        ///     Tracks a database table delete operation. A SQL DELETE statement will be generated using the specified 
        ///     ISqlDeleteBuilder object. When ISqlModelMapper.SaveChanges method is called, the SQL DELETE statement will be executed.
        /// </summary>
        /// <param name="deleteBuilder">An interface used to build the SQL DELETE statement.</param>
        /// <param name="parameters">
        ///     (Optional) One or more values that you want to use as arguments in the DELETE SQL statement defined in deleteBuilder.
        /// </param>
        /// <returns>Returns an <see cref="ISqlModelMapper"/> object, which can be used for executing other methods.</returns>
        ISqlModelMapper TrackSqlBuilder(ISqlDeleteBuilder deleteBuilder, params object[] parameters);

        /// <summary>
        ///     Tracks a database table update operation. A SQL UPDATE statement will be generated using the 
        ///     specified ISqlUpdateBuilder object. When ISqlModelMapper.SaveChanges method is called, 
        ///     the SQL UPDATE statement will be executed.
        /// </summary>
        /// <param name="updateBuilder">An <see cref="ISqlUpdateBuilder"/> object used to build the SQL UPDATE statement.</param>
        /// <param name="parameters">
        ///     One or more values that you want to use as arguments in the SQL UPDATE statement defined in updateBuilder.
        /// </param>
        /// <returns>Returns an <see cref="ISqlModelMapper"/> object, which can be used for executing other methods.</returns>
        ISqlModelMapper TrackSqlBuilder(ISqlUpdateBuilder updateBuilder, params object[] parameters);

        /// <summary>
        ///     Checks whether any record exists according to the retrieval criteria specified in a TModel class.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <param name="parameters">
        ///     (Optional) One or more values that you want to use as retrieval arguments 
        ///     in the SQL SELECT statement defined in TModel.
        /// </param>
        /// <returns>Returns whether any record exists.</returns>
        bool Exists<TModel>(params object[] parameters);

        /// <summary>
        ///     Checks whether data exists when retrieved, according to the primary key defined in a TModel class.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <param name="parameters">
        ///     (Optional) One or more values that you want to use as retrieval arguments in the SQL SELECT statement 
        ///     defined by the main table and its primary key in TModel.
        /// </param>
        /// <returns>Returns whether data exists.</returns>
        bool KeyExists<TModel>(params object[] parameters);

        /// <summary>
        ///     Gets the number of rows in the result set retrieved, according to the criteria specified in a TModel class.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <param name="parameters">
        ///     (Optional) One or more values that you want to use as retrieval arguments in the SQL SELECT statement 
        ///     defined in TModel.
        /// </param>
        /// <returns>Returns the number of rows in the database result set.</returns>
        int Count<TModel>(params object[] parameters);

        /// <summary>
        ///     Gets the number of all distinct values specified by the SQL expression, 
        ///     according to the criteria specified in a TModel class.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <param name="expression">A string of SQL expression used to clear up the duplicate data.</param>
        /// <param name="parameters">
        ///     (Optional) One or more values that you want to use as retrieval arguments in the SQL SELECT statement defined in TModel.
        /// </param>
        /// <returns>Returns the number of rows of the database result set, where duplicates have been cleared up.</returns>
        int DistinctCount<TModel>(string expression, params object[] parameters);

        /// <summary>
        ///     Gets the maximum value for the specified SQL expression, according to the retrieval 
        ///     criteria specified in a TModel class.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <param name="expression">A SQL expression string used to compute the maximum value.</param>
        /// <param name="parameters">
        /// (Optional) One or more values that you want to use as retrieval arguments in the SQL SELECT 
        /// statement defined in TModel.
        /// </param>
        /// <returns>
        ///     The maximum value of the retrieved data. Its data type is determined by the return value of the SQL expression.
        /// </returns>
        object Max<TModel>(string expression, params object[] parameters);

        /// <summary>
        ///     Gets the minimum value for the specified SQL expression, according to the retrieval criteria 
        ///     specified in a TModel class.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <param name="expression">A SQL expression string used to compute the minimum value.</param>
        /// <param name="parameters">
        ///     (Optional) One or more values that you want to use as retrieval arguments in the 
        ///     SQL SELECT statement defined in TModel.
        /// </param>
        /// <returns>
        ///     The minimum value of the retrieved data. Its data type is determined by the return value of the SQL expression.
        /// </returns>
        object Min<TModel>(string expression, params object[] parameters);

        /// <summary>
        ///     Computes the average value using the specified SQL expression for the data 
        ///     retrieved according to the criteria specified in a TModel class.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <param name="expression">A string of SQL expression used to compute the average value.</param>
        /// <param name="parameters">
        ///     (Optional) One or more values that you want to use as retrieval arguments in the SQL SELECT 
        ///     statement defined in TModel.
        /// </param>
        /// <returns>
        ///     The average value of the retrieved data. Its data type is determined by the return value of the SQL expression.
        /// </returns>
        object Avg<TModel>(string expression, params object[] parameters);

        /// <summary>
        ///     Computes the sum of the value using the specified SQL expression for the data retrieved 
        ///     according to the criteria specified in a TModel class.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <param name="expression">A string of SQL expression used to compute the sum of the value.</param>
        /// <param name="parameters">
        ///     (Optional) One or more values that you want to use as retrieval arguments in the SQL 
        ///     SELECT statement defined in TModel.
        /// </param>
        /// <returns>
        ///     The sum of the value of the retrieved data. Its data type is determined by the return value of the SQL expression.
        /// </returns>
        object Sum<TModel>(string expression, params object[] parameters);

        /// <summary>
        ///     Retrieves data from the first column, in the first row, for the specified SQL expression, 
        ///     according to the criteria specified in a TModel class.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <typeparam name="TValue">The type of the value retrieved.</typeparam>
        /// <param name="expression">
        ///     A SQL expression string used to get data from the first column in the first row.
        /// </param>
        /// <param name="parameters">
        ///     (Optional) One or more values that you want to use as retrieval arguments in the SQL 
        ///     SELECT statement defined in TModel.
        /// </param>
        /// <returns>
        ///     Returns the data from the first column in the first row, of the retrieved data. Its 
        ///     data type is determined by the return value of the SQL expression.
        /// </returns>
        TValue Scalar<TModel, TValue>(string expression, params object[] parameters);

        /// <summary>
        ///     Asynchronously retrieves data from the first column, in the first row, for the specified SQL expression, 
        ///     according to the criteria specified in a TModel class.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <typeparam name="TValue">The type of the value retrieved.</typeparam>
        /// <param name="expression">
        ///     A SQL expression string used to get data from the first column in the first row.
        /// </param>
        /// <param name="parameters">
        ///     (Optional) One or more values that you want to use as retrieval arguments in the SQL 
        ///     SELECT statement defined in TModel.
        /// </param>
        /// <returns>
        ///     Returns a task that represents the asynchronous operation.
        /// </returns>
        Task<TValue> ScalarAsync<TModel, TValue>(string expression, params object[] parameters);

        /// <summary>
        ///     Asynchronously retrieves data from the first column, in the first row, for the specified SQL expression, 
        ///     according to the criteria specified in a TModel class.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <typeparam name="TValue">The type of the value retrieved.</typeparam>
        /// <param name="expression">
        ///     A SQL expression string used to get data from the first column in the first row.
        /// </param>
        /// <param name="parameters">
        ///     (Optional) One or more values that you want to use as retrieval arguments in the SQL 
        ///     SELECT statement defined in TModel.
        /// </param>
        /// <param name="cancellationToken">
        ///     A cancellation token that can be used by other objects or threads to receive notice of cancellation.
        /// </param>
        /// <returns>
        ///     Returns a task that represents the asynchronous operation.
        /// </returns>
        Task<TValue> ScalarAsync<TModel, TValue>(
            string expression, object[] parameters, CancellationToken cancellationToken);

        /// <summary>
        ///     Retrieves data from the first column, in the first row, for the specified SQL 
        ///     expression according to the primary key in a TModel class.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <typeparam name="TValue">The type of the value retrieved.</typeparam>
        /// <param name="expression">
        ///     A SQL expression string used to get data from the first column in the first row.
        /// </param>
        /// <param name="parameters">
        ///     One or more values that you want to use as retrieval arguments in the SQL 
        ///     SELECT statement defined by the primary table and the primary key(s) in TModel.
        /// </param>
        /// <returns>
        ///     Returns the data from the first column in the first row of the retrieved data. 
        ///     Its data type is determined by the return value of the SQL expression.
        /// </returns>
        TValue ScalarByKey<TModel, TValue>(string expression, params object[] parameters);

        /// <summary>
        ///     Asynchronously retrieves data from the first column, in the first row, for the specified SQL 
        ///     expression according to the primary key in a TModel class.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <typeparam name="TValue">The type of the value retrieved.</typeparam>
        /// <param name="expression">
        ///     A SQL expression string used to get data from the first column in the first row.
        /// </param>
        /// <param name="parameters">
        ///     One or more values that you want to use as retrieval arguments in the SQL 
        ///     SELECT statement defined by the primary table and the primary key(s) in TModel.
        /// </param>
        /// <returns>
        ///     Returns a task that represents the asynchronous operation.
        /// </returns>
        Task<TValue> ScalarByKeyAsync<TModel, TValue>(string expression, params object[] parameters);

        /// <summary>
        ///     Asynchronously retrieves data from the first column, in the first row, for the specified SQL 
        ///     expression according to the primary key in a TModel class.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <typeparam name="TValue">The type of the value retrieved.</typeparam>
        /// <param name="expression">
        ///     A SQL expression string used to get data from the first column in the first row.
        /// </param>
        /// <param name="parameters">
        ///     One or more values that you want to use as retrieval arguments in the SQL 
        ///     SELECT statement defined by the primary table and the primary key(s) in TModel.
        /// </param>
        /// <param name="cancellationToken">
        ///     A cancellation token that can be used by other objects or threads to receive notice of cancellation.
        /// </param>
        /// <returns>
        ///     Returns a task that represents the asynchronous operation.
        /// </returns>
        Task<TValue> ScalarByKeyAsync<TModel, TValue>(
            string expression, object[] parameters, CancellationToken cancellationToken);

        /// <summary>
        ///     Saves all of the data changes to the database, by executing the database table operations 
        ///     tracked by the ISqlModelMapper object, and calls the tracked Action delegates during operations.
        /// </summary>
        /// <returns>
        ///     Returns an IDbResult object whose property can be used to conveniently get the result of 
        ///     the executed database operation.
        /// </returns>
        IDbResult SaveChanges();

        /// <summary>
        ///     Asynchronously saves all of the data changes to the database, by executing the database table operations 
        ///     tracked by the ISqlModelMapper object, and calls the tracked Action delegates during operations.
        /// </summary>
        /// <returns>
        ///     Returns a task that represents the asynchronous operation.
        /// </returns>
        Task<IDbResult> SaveChangesAsync();

        /// <summary>
        ///     Asynchronously saves all of the data changes to the database, by executing the database table operations 
        ///     tracked by the ISqlModelMapper object, and calls the tracked Action delegates during operations.
        /// </summary>
        /// <param name="cancellationToken">
        ///     A cancellation token that can be used by other objects or threads to receive notice of cancellation.
        /// </param>
        /// <returns>
        ///     Returns a task that represents the asynchronous operation.
        /// </returns>
        Task<IDbResult> SaveChangesAsync(CancellationToken cancellationToken);

        /// <summary>
        ///     Performs validity check to all data in the model tracked by the current ISqlModelMapper object.
        /// </summary>
        /// <returns>Whether the data in the model tracked has passed the validity check.</returns>
        bool ValidateTrackedModels();

        /// <summary>
        ///     Performs validity check to all data in the model tracked by the current <see cref="ISqlModelMapper"/> object and gets the validation result.
        /// </summary>
        /// <param name="ValidationResults">A <see cref="List{ValidationResult}"/> object that includes the data validation results.</param>
        /// <returns>Whether all of the data in the model object tracked has passed the validity check.</returns>
        bool ValidateTrackedModels(out List<ValidationResult> ValidationResults);

        /// <summary>
        ///     Clears all tracked information from a model.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <param name="model">The model object whose tracked information you want to remove.</param>
        /// <returns>
        ///     Returns true if the tracked information of the model object has been removed; 
        ///     returns false if tracked information of the model does not exist or the model is null.
        /// </returns>
        bool RemoveTrackedModel<TModel>(TModel model);

        /// <summary>
        ///     Clears all tracked information.
        /// </summary>
        void ClearTracked();

        /// <summary>
        ///     Gets the query conditions of a dynamic query.
        /// </summary>
        /// <typeparam name="TModel">The type of a model class.</typeparam>
        /// <returns>Returns a newly created IQueryBuilder object.</returns>
        IQueryBuilder<TModel> GetQueryBuilder<TModel>(bool removeWhereClause = false);
    }
}
